//From the desk of Frank P. Westlake; public domain.
package app.simple.inure.terminal.shortcuts;

import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.TextView;
import android.widget.Toast;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;

import app.simple.inure.R;
import app.simple.inure.extensions.activities.BaseActivity;

public class FSNavigator extends BaseActivity {
    
    private final int ACTION_THEME_SWAP = 0x00000100;
    private final int BUTTON_SIZE = 150;
    private final android.content.Context context = this;
    private final float textLg = 24;
    private int theme = android.R.style.Theme;
    private SharedPreferences SP;
    private File cd;
    private File extSdCardFile;
    private String extSdCard;
    private HashMap <Integer, LinearLayout> cachedFileView;
    private HashMap <Integer, LinearLayout> cachedDirectoryView;
    private HashMap <Integer, TextView> cachedDividerView;
    private int countFileView;
    private int countDirectoryView;
    private int countDividerView;
    private LinearLayout contentView;
    private LinearLayout titleView;
    private LinearLayout pathEntryView;
    
    ////////////////////////////////////////////////////////////
    public void onCreate(android.os.Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setTitle("getString(R.string.fsnavigator_title)"); //"File Selector");
        SP = PreferenceManager.getDefaultSharedPreferences(context);
        theme = SP.getInt("theme", theme);
        setTheme(theme);
        getWindow().setSoftInputMode(android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        
        Intent intent = getIntent();
        extSdCardFile = Environment.getExternalStorageDirectory();
        extSdCard = getCanonicalPath(extSdCardFile);
        Uri uri = intent.getData();
        String path = uri == null ? null : uri.getPath();
        if (null == path || null == (chdir(path))) {
            chdir(extSdCard);
        }
        
        if (intent.hasExtra("title")) {
            setTitle(intent.getStringExtra("title"));
        }
        
        titleView = directoryEntry("..");
        pathEntryView = fileEntry(null);
        contentView = makeContentView();
        cachedDirectoryView = new HashMap <Integer, LinearLayout>();
        cachedFileView = new HashMap <Integer, LinearLayout>();
        cachedDividerView = new HashMap <Integer, TextView>();
    }
    
    ////////////////////////////////////////////////////////////
    public void onPause() {
        super.onPause();
        doPause();
    }
    
    ////////////////////////////////////////////////////////////
    private void doPause() {
        SP.edit().putString("lastDirectory", getCanonicalPath(cd)).commit();
    }
    
    ////////////////////////////////////////////////////////////
    public void onResume() {
        super.onResume();
        doResume();
    }
    
    ////////////////////////////////////////////////////////////
    private void doResume() {
        makeView();
    }
    
    ////////////////////////////////////////////////////////////
    private void swapTheme() {
        switch (theme) {
            case android.R.style.Theme:
                theme = android.R.style.Theme_Light;
                break;
            case android.R.style.Theme_Light:
                theme = android.R.style.Theme;
                break;
            default:
                return;
        }
        SP.edit().putInt("theme", theme).commit();
        startActivityForResult(getIntent().addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT), -1);
        finish();
    }
    
    ////////////////////////////////////////////////////////////
    private String ifAvailable(String goTo) {
        if (goTo.startsWith(extSdCard)) {
            String s = Environment.getExternalStorageState();
            if (s.equals(Environment.MEDIA_MOUNTED)
                    || s.equals(Environment.MEDIA_MOUNTED_READ_ONLY)
            ) {
                return (goTo);
            }
            toast("getString(R.string.fsnavigator_no_external_storage)", 1);//"External storage not available", 1);
            return (extSdCard);
        }
        return (goTo);
    }
    
    ////////////////////////////////////////////////////////////
    private File chdir(File file) {
        String path = ifAvailable(getCanonicalPath(file));
        System.setProperty("user.dir", path);
        return (cd = new File(path));
    }
    
    private File chdir(String path) {
        return (chdir(new File(path)));
    }
    
    ////////////////////////////////////////////////////////////
    private TextView entryDividerH() {
        TextView tv;
        if (countDividerView < cachedDividerView.size()) {
            tv = cachedDividerView.get(countDividerView);
        } else {
            tv = new TextView(context);
            tv.setLayoutParams(
                    new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.FILL_PARENT
                            , 1
                            , 1
                    )
                              );
            cachedDividerView.put(countDividerView, tv);
        }
        ++countDividerView;
        return (tv);
    }
    
    ////////////////////////////////////////////////////////////
    View.OnClickListener fileListener = new View.OnClickListener() {
        public void onClick(View view) {
            String path = (String) view.getTag();
            if (path != null) {
                setResult(RESULT_OK, getIntent().setData(Uri.fromFile(new File(cd, path))));
                finish();
            }
        }
    };
    
    ////////////////////////////////////////////////////////////
    private LinearLayout fileView(boolean entryWindow) {
        LinearLayout ll = new LinearLayout(context);
        ll.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , LinearLayout.LayoutParams.WRAP_CONTENT
                        , 1
                )
                          );
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setGravity(Gravity.FILL);
        final TextView tv;
        if (entryWindow) {
            tv = new EditText(context);
            tv.setHint("getString(R.string.fsnavigator_optional_enter_path)");
            tv.setLayoutParams(
                    new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.FILL_PARENT
                            , LinearLayout.LayoutParams.FILL_PARENT
                            , 2
                    )
                              );
            tv.setOnKeyListener(
                    new EditText.OnKeyListener() {
                        public boolean onKey(View v, int keyCode, KeyEvent event) {
                            if (keyCode == KeyEvent.KEYCODE_ENTER) {
                                String path = tv.getText().toString();
                                File file = new File(getCanonicalPath(path));
                                chdir(file.getParentFile() == null ? file : file.getParentFile());
                                if (file.isFile()) {
                                    setResult(RESULT_OK, getIntent().setData(Uri.fromFile(file)));
                                    finish();
                                } else {
                                    chdir(file);
                                    makeView();
                                }
                                return (true);
                            }
                            return (false);
                        }
                    }
                               );
            ll.addView(tv);
        } else {
            tv = new TextView(context);
            tv.setClickable(true);
            tv.setLongClickable(true);
            tv.setOnClickListener(fileListener);
            tv.setLayoutParams(
                    new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.FILL_PARENT
                            , LinearLayout.LayoutParams.FILL_PARENT
                            , 1
                    )
                              );
            HorizontalScrollView hv = new HorizontalScrollView(context);
            hv.setFillViewport(true);
            hv.setLayoutParams(
                    new LinearLayout.LayoutParams(
                            LinearLayout.LayoutParams.FILL_PARENT
                            , BUTTON_SIZE
                            , 7
                    )
                              );
            hv.addView(tv);
            ll.addView(hv);
        }
        tv.setFocusable(true);
        tv.setSingleLine();
        tv.setTextSize(textLg);
        tv.setTypeface(Typeface.SERIF, Typeface.BOLD);
        tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
        tv.setPadding(10, 5, 10, 5);
        tv.setId(R.id.textview); //1);
        
        return (ll);
    }
    
    ////////////////////////////////////////////////////////////
    private LinearLayout fileEntry(final String entry) {
        LinearLayout ll;
        if (entry == null) {
            ll = fileView(entry == null);
        } else {
            if (countFileView < cachedFileView.size()) {
                ll = cachedFileView.get(countFileView);
            } else {
                cachedFileView.put(countFileView, ll = fileView(entry == null));
            }
            ++countFileView;
        }
        TextView tv = ll.findViewById(R.id.textview);
        tv.setText(entry == null ? "" : entry);
        tv.setTag(entry == null ? "" : entry);
        return (ll);
    }
    
    ////////////////////////////////////////////////////////////
    private ImageView imageViewFolder(boolean up) {
        ImageView b1 = new ImageView(context);
        b1.setClickable(true);
        b1.setFocusable(true);
        b1.setId(R.id.imageview);
        b1.setLayoutParams(
                new LinearLayout.LayoutParams(
                        120
                        , 120
                        , 1
                )
                          );
        b1.setImageResource(up ? R.drawable.ic_folder_up : R.drawable.ic_snippet_folder);
        b1.setOnClickListener(directoryListener);
        b1.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        return (b1);
    }
    
    ////////////////////////////////////////////////////////////
    View.OnClickListener directoryListener = new View.OnClickListener() {
        public void onClick(View view) {
            String path = (String) view.getTag();
            if (path != null) {
                File file = new File(path);
                if (file.isFile()) {
                    setResult(RESULT_OK, getIntent().setData(Uri.fromFile(file)));
                    finish();
                } else {
                    chdir(file);
                }
                makeView();
            }
        }
    };
    
    ////////////////////////////////////////////////////////////
    private LinearLayout directoryView(boolean up) {
        ImageView b1 = imageViewFolder(up);
        TextView tv = new TextView(context);
        if (up) {
            tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);//Gravity.CENTER);
        } else {
            tv.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
        }
        tv.setClickable(true);
        tv.setLongClickable(true);
        tv.setFocusable(true);
        tv.setOnClickListener(directoryListener);
        tv.setMaxLines(1);
        tv.setTextSize(textLg);
        tv.setPadding(10, 5, 10, 5);
        tv.setId(R.id.textview);
        tv.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , BUTTON_SIZE
                        , 1
                )
                          );
        HorizontalScrollView hv = new HorizontalScrollView(context);
        hv.addView(tv);
        hv.setFillViewport(true);
        hv.setFocusable(true);
        hv.setOnClickListener(directoryListener);
        hv.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , BUTTON_SIZE
                        , 7
                )
                          );
        LinearLayout ll = new LinearLayout(context);
        ll.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , BUTTON_SIZE
                        , 2
                )
                          );
        ll.setOrientation(LinearLayout.HORIZONTAL);
        ll.setGravity(Gravity.FILL);
        ll.setOnClickListener(directoryListener);
        ll.addView(b1);
        ll.addView(hv);
        
        return (ll);
    }
    
    ////////////////////////////////////////////////////////////
    private LinearLayout directoryEntry(final String name) {
        boolean up = name.equals("..");
        LinearLayout linearLayout;
        if (up) {
            linearLayout = directoryView(up);
        } else {
            if (countDirectoryView < cachedDirectoryView.size()) {
                linearLayout = cachedDirectoryView.get(countDirectoryView);
            } else {
                linearLayout = directoryView(up);
                cachedDirectoryView.put(countDirectoryView, linearLayout);
            }
            ++countDirectoryView;
        }
        
        TextView tv = linearLayout.findViewById(R.id.textview);
        tv.setTag(name);
        tv.setText(up ? "[" + cd.getPath() + "]"
                        : name
                  );
        linearLayout.findViewById(R.id.imageview).setTag(name);
        return (linearLayout);
    }
    
    ////////////////////////////////////////////////////////////
    public boolean onKeyUp(int keyCode, KeyEvent event) {
        if ((keyCode == KeyEvent.KEYCODE_BACK)) {
            finish();
            return (true);
        } else {
            return (super.onKeyUp(keyCode, event));
        }
    }
    
    ////////////////////////////////////////////////////////////
    private LinearLayout makeContentView() {
        final LinearLayout linearLayout = new LinearLayout(context);
        linearLayout.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , LinearLayout.LayoutParams.WRAP_CONTENT
                        , 1
                )
                                    );
        linearLayout.setId(R.id.mainview);
        linearLayout.setOrientation(LinearLayout.VERTICAL);
        linearLayout.setGravity(Gravity.FILL);
        final ScrollView sv = new ScrollView(context);
        sv.setId(R.id.scrollview);
        sv.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , LinearLayout.LayoutParams.WRAP_CONTENT
                        , 1
                )
                          );
        sv.addView(linearLayout);
        final LinearLayout bg = new LinearLayout(context);
        bg.setLayoutParams(
                new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.FILL_PARENT
                        , LinearLayout.LayoutParams.WRAP_CONTENT
                        , 1
                )
                          );
        bg.setOrientation(LinearLayout.VERTICAL);
        bg.setGravity(Gravity.FILL);
        bg.setTag(linearLayout);
        bg.addView(
                titleView
                , android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT
                  );
        bg.addView(sv);
        bg.addView(
                pathEntryView
                , android.view.ViewGroup.LayoutParams.FILL_PARENT, android.view.ViewGroup.LayoutParams.WRAP_CONTENT
                  );
        return (bg);
    }
    
    ////////////////////////////////////////////////////////////
    private void makeView() {
        countDirectoryView = countFileView = 0;
        ScrollView scrollView = contentView.findViewById(R.id.scrollview);
        LinearLayout linearLayout = scrollView.findViewById(R.id.mainview);
        linearLayout.removeAllViews();
        if (cd == null) {
            chdir("/");
        }
        String path = getCanonicalPath(cd);
        
        if (path.equals("")) {
            chdir(path = "/");
        }
        if (path.equals("/")) {
            titleView.setVisibility(View.GONE);
        } else {
            titleView.setVisibility(View.VISIBLE);
            titleView.requestLayout();
            ((TextView) titleView.findViewById(R.id.textview)).setText("[" + cd.getPath() + "]");
        }
        
        String[] zd = cd.list(new java.io.FilenameFilter() {
            public boolean accept(File file, String name) {
                return (new File(file, name).isDirectory());
            }
        });
        if (zd != null) {
            java.util.Arrays.sort(zd, 0, zd.length, stringSortComparator);
            for (int i = 0, n = zd.length; i < n; i++) {
                if (zd[i].equals(".")) {
                    continue;
                }
                linearLayout.addView(directoryEntry(zd[i]));
                linearLayout.addView(entryDividerH());
            }
        }
        String[] zf = cd.list(new java.io.FilenameFilter() {
            public boolean accept(File file, String name) {
                return (!(new File(file, name).isDirectory()));
            }
        });
        if (zf != null) {
            java.util.Arrays.sort(zf, 0, zf.length, stringSortComparator);
            for (int i = 0, n = zf.length; i < n; i++) {
                linearLayout.addView(fileEntry(zf[i]));
                linearLayout.addView(entryDividerH());
            }
        }
        ((TextView) pathEntryView.findViewById(R.id.textview)).setText("");
        scrollView.scrollTo(0, 0);
        //    titleView.setSelected(true);
        setContentView(contentView);
    }
    
    //////////////////////////////////////////////////////////////////////
    java.util.Comparator <String> stringSortComparator = new java.util.Comparator <String>() {
        public int compare(String a, String b) {
            return (a.toLowerCase().compareTo(b.toLowerCase()));
        }
    };
    
    //////////////////////////////////////////////////////////////////////
    String getCanonicalPath(String path) {
        return (getCanonicalPath(new File(path)));
    }
    
    String getCanonicalPath(File file) {
        try {
            return (file.getCanonicalPath());
        } catch (IOException e) {
            return (file.getPath());
        }
    }
    
    //////////////////////////////////////////////////////////////////////
    public boolean onCreateOptionsMenu(Menu menu)
    //  public boolean onPrepareOptionsMenu(Menu menu)
    {
        super.onCreateOptionsMenu(menu);
        //    super.onPrepareOptionsMenu(menu);    menu.clear();
        menu.add(0, ACTION_THEME_SWAP, 0, "getString(R.string.fsnavigator_change_theme)");//"Change theme");
        return (true);
    }
    
    //////////////////////////////////////////////////////////////////////
    public boolean onOptionsItemSelected(MenuItem item) {
        super.onOptionsItemSelected(item);
        return (doOptionsItem(item.getItemId()));
    }
    
    //////////////////////////////////////////////////////////////////////
    private boolean doOptionsItem(int itemId) {
        switch (itemId) {
            case ACTION_THEME_SWAP:
                swapTheme();
                return (true);
        }
        return (false);
    }
    
    //////////////////////////////////////////////////////////////////////
    //  private void toast(final String message){toast(message, 0);}
    private void toast(final String message, final int duration) {
        runOnUiThread(
                new Runnable() {
                    public void run() {
                        Toast.makeText(context, message, duration == 0 ? Toast.LENGTH_SHORT : Toast.LENGTH_LONG).show();
                    }
                }
                     );
    }
    //////////////////////////////////////////////////////////////////////
}
